package com.ecr.hub.front.bean.managed;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletResponse;

import org.richfaces.event.FileUploadEvent;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;

import com.ecr.hub.ApplicationException;
import com.ecr.hub.front.bean.AbstractManagedBean;
import com.ecr.hub.model.HubInputData;
import com.ecr.hub.model.enumeration.HubTypeFile;
import com.ecr.hub.service.data.input.IInputDataManager;

@Controller("inputDataFileManaged")
@Scope("session")
public class InputDataFileManagedBean extends AbstractManagedBean {

	private static final long serialVersionUID = 1L;

	// Valeur par défaut pour la lecture du buffer.
	public int DEFAULT_BUFFER_SIZE = 1024;

	// Le nom du fichier à charger.
	private String fileName;

	// La liste représentant la table de chargement des fichiers.
	private List<HubInputData> lstInputData;

	// Le chargement sur lequel le coordinateur intervient.
	private HubInputData currentInputData;

	// Le répertoire de stockage des fichiers.
	@Value(value = "${repository.folder}")
	private String repositoryFolder;

	@Resource(name = "inputDataManager")
	private transient IInputDataManager inputDataManager;

	/**
	 * Récupération de la totalité des enregistrements dans la table
	 * hub_input_data.
	 */
	@PostConstruct
	public void _getAllList() {
		try {
			setLstInputData(inputDataManager.getListAll());
		} catch (Exception e) {
			getErrorHandler(e);
		}
	}

	/**
	 * Charge un fichier situé en dehors de l'application (sur un repertoire
	 * placé n'importe ou sur la machine qui héberge l'application). On lit le
	 * fichier et on crée un flux sur la sortie.
	 */
	// TODO : a voir si et comment on déplace dans le manager.
	public void downloadFile() {

		BufferedInputStream bufferedInputStream = null;
		BufferedOutputStream bufferedOutputStream = null;

		try {
			FacesContext context = FacesContext.getCurrentInstance();
			ExternalContext externalContext = context.getExternalContext();
			HttpServletResponse httpServletResponse = (HttpServletResponse) externalContext
					.getResponse();

			File file = new File(repositoryFolder + fileName);

			bufferedInputStream = new BufferedInputStream(new FileInputStream(
					file), DEFAULT_BUFFER_SIZE);
			httpServletResponse.reset();
			httpServletResponse.setContentType("application/force-download");
			httpServletResponse.setContentLength((int) file.length());
			httpServletResponse.setHeader("Content-disposition",
					"attachment; filename=\"" + fileName + "\"");
			bufferedOutputStream = new BufferedOutputStream(
					httpServletResponse.getOutputStream(), DEFAULT_BUFFER_SIZE);
			byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
			int length;
			while ((length = bufferedInputStream.read(buffer)) > 0) {
				bufferedOutputStream.write(buffer, 0, length);
			}
			bufferedOutputStream.flush();

			context.responseComplete();
		} catch (Exception e) {
			getErrorHandler(e);
		} finally {
			try {
				bufferedOutputStream.close();
				bufferedInputStream.close();
			} catch (IOException e) {
				getErrorHandler(e);
			}
		}
	}

	/**
	 * Suppression d'une ligne de chargement. Ligne de chargement = fichier dans
	 * le répertoire de stockage et ligne de statut dans la table
	 * hub_input_data.
	 */
	public void delete() {
		try {
			inputDataManager.delete(getCurrentInputData());
			_getAllList();
		} catch (ApplicationException e) {
			getErrorHandler(e);
		}
	}

	/**
	 * Récupération d'un fichier de sillon à écrire dans le répertoire de
	 * stockage. On prend le fichier, on le stocke et on écrit une ligne dans la
	 * table hub_input_data.
	 */
	public void sillonListener(FileUploadEvent event) throws Exception {
		try {
			inputDataManager.uploadFile(event, HubTypeFile.SILLON);
			_getAllList();
		} catch (ApplicationException e) {
			getErrorHandler(e);
		}
	}

	/**
	 * Récupération d'un fichier de composition à écrire dans le répertoire de
	 * stockage. On prend le fichier, on le stocke et on écrit une ligne dans la
	 * table hub_input_data.
	 */
	public void compositionListener(FileUploadEvent event) throws Exception {
		try {
			inputDataManager.uploadFile(event, HubTypeFile.COMPOSITION);
			_getAllList();
		} catch (ApplicationException e) {
			getErrorHandler(e);
		}
	}
	
	// *********************************
	// Les getters et les setters.
	// *********************************

	public String getFileName() {
		return fileName;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}

	public List<HubInputData> getLstInputData() {
		return lstInputData;
	}

	public void setLstInputData(List<HubInputData> lstInputData) {
		this.lstInputData = lstInputData;
	}

	public HubInputData getCurrentInputData() {
		return currentInputData;
	}

	public void setCurrentInputData(HubInputData currentInputData) {
		this.currentInputData = currentInputData;
	}
}
